package com.keyingbo.orm.framework.util;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

/**
 * 
 * 
 * <pre>
 * 扫描辅助类。
 * </pre>
 * 
 * @author luxiaocheng luxc1@midea.com.cn
 * @version 1.00.00
 * 
 *          <pre>
 * 修改记录
 *    修改后版本:     修改人：  修改日期:     修改内容:
 * </pre>
 */
public class ScanUtils {

	private static final Log log = LogFactory.getLog(ScanUtils.class);

	private static final String ENTITY_LOCATION_PATTERN = "classpath*:com/keyingbo/**/entity*/*.class";
	private static final ResourcePatternResolver RESOLVER = new PathMatchingResourcePatternResolver();
	private static final MetadataReaderFactory READER_FACTORY = new SimpleMetadataReaderFactory();

	public static List<Class<?>> scanEntityClasses(Class<?> annoClazz){
		List<MetadataReader> readers = scanEntity(ENTITY_LOCATION_PATTERN);
		return scanClass(readers, null, annoClazz);
	}

	private static List<MetadataReader> scanEntity(String pattern) {
		List<MetadataReader> list = new ArrayList<MetadataReader>();
		try {
			Resource[] resources = RESOLVER.getResources(ENTITY_LOCATION_PATTERN);
			for (Resource res : resources) {
				MetadataReader meta = READER_FACTORY.getMetadataReader(res);
				list.add(meta);
			}
		} catch (IOException e) {
			log.error("读取类文件时发生I/O错误。", e);
		}
		return list;
	}
	private static List<Class<?>> scanClass(List<MetadataReader> metas,Class<?> superClazz, Class<?> annoClazz) {
		List<Class<?>> ret = new ArrayList<Class<?>>();
		String annoName = annoClazz.getName();
		for (MetadataReader reader : metas) {
			if(annoClazz!=null){
				Set<String> annotationTypes = reader.getAnnotationMetadata().getAnnotationTypes();
				if (!annotationTypes.contains(annoName)) {
					continue;
				}
			}
			Class<?> clazz = null;
			String name = reader.getClassMetadata().getClassName();
			try {
				clazz = Class.forName(name);
			} catch (ClassNotFoundException e) {
				log.error("类加载不成功，找不到类文件。", e);
				continue;
			}
			if(superClazz!=null){
				if (!superClazz.isAssignableFrom(clazz)) {
					continue;
				}
			}
			ret.add(clazz);
		}
		return ret;
	}
	
	/**
	 * 例如 classpath星号:com/midea/星号星号/entity/星号.class
	 * @param patternLocation
	 * @return
	 */
	public static List<Class<?>> scanClassesByPatternLocation(String patternLocation){
		List<Class<?>> listClass=new ArrayList<Class<?>>();
		List<MetadataReader> list = new ArrayList<MetadataReader>();
		try {
			Resource[] resources = RESOLVER.getResources(patternLocation);
			for (Resource res : resources) {
				MetadataReader meta = READER_FACTORY.getMetadataReader(res);

				Set<String> annotationTypes = meta.getAnnotationMetadata().getAnnotationTypes();
				Class<?> clazz = null;
				String name = meta.getClassMetadata().getClassName();
				try {
					clazz = Class.forName(name);
					listClass.add(clazz);
					
					Annotation[] arrAnnotation =clazz.getAnnotations();
					if( arrAnnotation!=null ){
						for(Annotation annotationTemp : arrAnnotation ){
							System.out.println("ScanUtils:Annotation:"+annotationTemp.getClass().getInterfaces()[0]);
						}
					}
					
				} catch (ClassNotFoundException e) {
					log.error("类加载不成功，找不到类文件。", e);
					continue;
				}
			}
			
			
		} catch (IOException e) {
			log.error("读取类文件时发生I/O错误。", e);
		}
		
		return listClass;
		
	}
	
	/**
	 * 例如 classpath星号:com/midea/星号星号/entity/星号.class
	 * @param patternLocation
	 * @return
	 */
	public static List<Map<String,Object>> scanClassesAnnotationByPatternLocation(String patternLocation){
		List<Map<String,Object>> listResult =new ArrayList<Map<String,Object>>();
		
		try {
			Resource[] resources = RESOLVER.getResources(patternLocation);
			for (Resource res : resources) {
				MetadataReader meta = READER_FACTORY.getMetadataReader(res);
				Class<?> clazz = null;
				String name = meta.getClassMetadata().getClassName();
				try {
					clazz = Class.forName(name);
				
					Map<String,Object> mapTemp =new HashMap<String, Object>();
					
					mapTemp.put("class", clazz);
					
					Map<String,Object> mapAnnotationTemp =new HashMap<String, Object>();
					
					Annotation[] arrAnnotation =clazz.getAnnotations();
					if( arrAnnotation!=null && arrAnnotation.length>0 ){
						for(Annotation annotationTemp : arrAnnotation ){
							mapAnnotationTemp.put(annotationTemp.getClass().getInterfaces()[0].getName(), annotationTemp);
						}
					}
					mapTemp.put("annotation", mapAnnotationTemp);
					
					listResult.add(mapTemp);
					
				} catch (ClassNotFoundException e) {
					log.error("类加载不成功，找不到类文件。", e);
					continue;
				}
			}
			
			
		} catch (IOException e) {
			log.error("读取类文件时发生I/O错误。", e);
		}
		
		return listResult;
		
	}
	
	public static void main(String[] args) {
		ScanUtils.scanClassesByPatternLocation("classpath*:com/keyingbo/**/job/*.class");
	}
}
